package com.sloth.bear.interceptor;

import com.sloth.bear.annotation.NoAuth;
import com.sloth.bear.util.JwtUtils;
import com.sloth.bear.util.UserContext;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

/**
 * 认证拦截器
 * 拦截所有请求进行鉴权，带有@NoAuth注解的接口除外
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class AuthInterceptor implements HandlerInterceptor {

    private final JwtUtils jwtUtils;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 如果不是方法处理器，直接放行
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        HandlerMethod handlerMethod = (HandlerMethod) handler;

        // 检查方法或类上是否有@NoAuth注解
        NoAuth methodAnnotation = handlerMethod.getMethodAnnotation(NoAuth.class);
        NoAuth classAnnotation = handlerMethod.getBeanType().getAnnotation(NoAuth.class);

        // 如果有@NoAuth注解，跳过鉴权
        if (methodAnnotation != null || classAnnotation != null) {
            log.debug("接口 {} 标记为@NoAuth，跳过鉴权", handlerMethod.getMethod().getName());
            return true;
        }

        try {
            // 从请求头获取token
            String token = getTokenFromRequest(request);

            if (!StringUtils.hasText(token)) {
                // 没有token，返回401
                log.warn("请求未携带token");
                return sendUnauthorizedResponse(response, "未登录或登录已过期，请先登录");
            }

            // 验证token有效性
            String username = jwtUtils.getUsernameFromToken(token);
            if (StringUtils.hasText(username) && jwtUtils.validateToken(token, username)) {
                // 解析用户信息并设置到上下文
                Long userId = jwtUtils.getUserIdFromToken(token);
                UserContext.setUserId(userId);
                UserContext.setUsername(username);

                log.debug("用户认证成功: userId={}, username={}", userId, username);
                return true;
            } else {
                // Token无效，返回401
                log.warn("Token验证失败，无效的token: {}", token.substring(0, Math.min(token.length(), 20)) + "...");
                return sendUnauthorizedResponse(response, "Token无效或已过期，请重新登录");
            }
        } catch (Exception e) {
            log.warn("Token解析失败: {}", e.getMessage());
            // Token解析失败，返回401
            return sendUnauthorizedResponse(response, "Token解析失败，请重新登录");
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        // 清除当前线程的用户上下文，避免内存泄漏
        UserContext.clear();
    }

    /**
     * 发送401未授权响应
     */
    private boolean sendUnauthorizedResponse(HttpServletResponse response, String message) {
        try {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write(String.format(
                "{\"code\": 401, \"message\": \"%s\", \"data\": null}", 
                message.replace("\"", "\\\"")
            ));
            response.getWriter().flush();
            return false;
        } catch (Exception e) {
            log.error("发送401响应失败", e);
            return false;
        }
    }

    /**
     * 从请求中获取token
     * 支持Authorization header和query parameter两种方式
     */
    private String getTokenFromRequest(HttpServletRequest request) {
        // 优先从Authorization header获取
        String bearerToken = request.getHeader("Authorization");
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        
        // 从query parameter获取
        return request.getParameter("token");
    }
}